//gcc -g  mqtt_ota_demo.c  -lcurl -lssl -lcrypto -lpaho-mqtt3as -lcjson
/**
 * @copyright Copyright (c) 2025 
 * CSG Digital Grid Technology (Guangdong) Co., Ltd.
 * @author xxxcsg
 * @brief MQTT 协议 OTA 升级客户端 Demo（适配 HIPH3519 设备）
 * @details 基于 MQTT 协议与远程服务器通信，实现设备固件升级及状态上报功能，核心能力如下：
 *          1. MQTT 连接管理：支持与指定服务器（60.204.219.164:1883）建立/重连/断开连接，配置 SSL 加密
 *          2. 主题订阅与发布：订阅 RPC 请求主题（接收升级指令），发布遥测数据、设备属性、升级进度等信息
 *          3. OTA 升级流程：接收 "update" RPC 指令后，通过 HTTP 接口获取固件信息（版本、大小、校验和），下载固件到本地（/userdata/upgrade/spfirmware.bin），并上报升级进度
 *          4. 设备信息上报：支持响应 "static info" RPC 请求，上报设备静态信息；启动时自动上报设备属性
 *          5. 日志与回调：提供统一日志输出接口，支持连接状态、消息收发等事件的回调处理
 * @note 1. 编译依赖：curl（HTTP 通信）、ssl/crypto（加密）、paho-mqtt3as（MQTT 客户端）、cjson（JSON 解析）
 *       2. 配置信息：设备令牌（TOKEN=HIPH3519）、服务器地址端口、MQTT 主题前缀等已固化定义，可根据实际环境调整
 *       3. 入口函数：默认提供 mqtt_ota_demo() 接口（适配嵌入式系统调用），预留 main() 函数入口（注释状态）
 *       4. 依赖模块：static_info.h（设备静态信息获取）、hota_updater.h（升级相关声明）
 * @attention 1. 运行前需确保目标设备已安装依赖库，且具备网络访问权限、/userdata/upgrade 目录读写权限
 *            2. 固件下载路径（/userdata/upgrade/spfirmware.bin）固定，需确保磁盘空间充足（匹配固件大小）
 *            3. SSL 信任证书默认路径为 ./mqttClientTrustCert.pem，可通过 g_pcCertPath 配置自定义路径
 *            4. 服务器地址、端口、令牌等配置需与服务端保持一致，否则无法正常通信
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <curl/curl.h>
#include <MQTTAsync.h>
#include <cJSON.h>
#include <stdbool.h> // 添加这个头文件以使用 bool 类型
#include <stdarg.h> // 对于C程序  

#include "static_info.h"
#include "hota_updater.h"
// 定义常量
#define SERVER_IP "60.204.219.164"
#define SERVER_PORT 1883
//#define TOKEN "nJCqAMFJkHwYaoLjMsri"
#define TOKEN "HIPH3519"
#define BASE_TOPIC "v1/devices/me/"
#define TELEMETRY_TOPIC BASE_TOPIC "telemetry"
#define RPC_REQUEST_TOPIC BASE_TOPIC "rpc/request/+"
#define RPC_RESPONSE_TOPIC_PREFIX BASE_TOPIC "rpc/response/"
#define RPC_REQUEST_PREFIX BASE_TOPIC "rpc/request/"
#define ADDRESS "tcp://60.204.219.164:1883"
#define TOPIC_ATTRS "v1/gateway/attributes"
#define TOPIC_ATTRS_EX BASE_TOPIC "attributes"

static int msgarrvd(void* context, char* topicName, int topicLen, MQTTAsync_message* message);

struct MemoryStruct {
  char *memory;
  size_t size;
};
static size_t
WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp)
{
  size_t realsize = size * nmemb;
  struct MemoryStruct *mem = (struct MemoryStruct *)userp;
 
 // 注意这里根据每次被调用获得的数据重新动态分配缓存区的大小
  char *ptr = realloc(mem->memory, mem->size + realsize + 1); 
  if(ptr == NULL) {
    /* out of memory! */ 
    printf("not enough memory (realloc returned NULL)\n");
    return 0;
  }
 
  mem->memory = ptr;
  memcpy(&(mem->memory[mem->size]), contents, realsize);
  mem->size += realsize;
  mem->memory[mem->size] = 0;
 
  return realsize;
}


int MQTT_connect();
// 统一处理 GET 请求的函数
CURLcode performGetRequest(const char *url, const char *params,struct MemoryStruct *chunk)
{
    CURL *curl;
    CURLcode res;
    printf("performGetRequest url:%s; params:%s;\n", url, params);
  
    curl_global_init(CURL_GLOBAL_DEFAULT);
    curl = curl_easy_init();
    if (curl)
    {
        char fullUrl[1024];
        snprintf(fullUrl, sizeof(fullUrl), "%s?%s", url, params);
        printf("curl  %s\n", fullUrl); // 添加调试输出
        curl_easy_setopt(curl, CURLOPT_URL, fullUrl);
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, chunk);

        res = curl_easy_perform(curl);
        if (res != CURLE_OK)
        {
            fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
        }

        curl_easy_cleanup(curl);
    }
    curl_global_cleanup();
    return res;
}

// 获取固件信息并下载 OTA 包的函数
void get_firmware_info_and_download()
{
  // 获取固件信息
  const char *url1 = "http://" SERVER_IP ":8080/api/v1/" TOKEN "/attributes";
  const char *params1 = "sharedKeys=fw_checksum&sharedKeys=fw_checksum_algorithm&sharedKeys=fw_size&sharedKeys=fw_title&sharedKeys=fw_version";
  struct MemoryStruct chunk;
  chunk.memory = malloc(1);  /* will be grown as needed by the realloc above */ 
  chunk.size = 0;    /* no data at this point */

  CURLcode res = performGetRequest(url1, params1,&chunk);

     printf("Response 1: %s\n", chunk.memory);

    // 解析 JSON 响应
    cJSON *parsed_json = cJSON_Parse(chunk.memory);
    cJSON *shared = cJSON_GetObjectItem(parsed_json, "shared");
    cJSON *fw_title = cJSON_GetObjectItem(shared, "fw_title");
    cJSON *fw_version = cJSON_GetObjectItem(shared, "fw_version");
    cJSON *fw_size = cJSON_GetObjectItem(shared, "fw_size");

    const char *title = cJSON_GetStringValue(fw_title);
    const char *version = cJSON_GetStringValue(fw_version);
    int size = fw_size->valueint;

    // 构建第二个请求的参数 下载固件
    char params2[256];
    snprintf(params2, sizeof(params2), "title=%s&version=%s&size=%d&chunk=0", title, version, size);

    const char *url2 = "http://" SERVER_IP ":8080/api/v1/" TOKEN "/firmware";
    
    free(chunk.memory);
    chunk.memory = malloc(1);  /* will be grown as needed by the realloc above */ 
    chunk.size = 0;    /* no data at this point */
    res = performGetRequest(url2, params2,&chunk);
    printf("Response 2: %s\n", chunk.memory);
    const char *firmware_filename = "/userdata/upgrade/spfirmware.bin";
    FILE * fp = fopen(firmware_filename, "wb");
    if (fp)
    {
        size_t written = fwrite(chunk.memory, 1, chunk.size, fp);  
        if (written != chunk.size)
        {
             fprintf(stderr, "Failed to open file written %lu != chunk.size %lu\n", written, chunk.size);
        }
        
        fclose(fp);
    }
    else{
        fprintf(stderr, "Failed to open file %s\n", firmware_filename);
    }
    free(chunk.memory);

  cJSON_Delete(parsed_json);
}


#define HW_TRUE      1 /**< Indicates HW_TRUE */
#define HW_FALSE     0 /**< Indicates HW_FALSE */

#define HW_SUCCESS   0 /**< Indicates success */
#define HW_FAILED    1 /**< Indicates failed */
#define HW_NULL     ((void *)0) /**< Indicates null ptr */  

typedef int            HW_INT;  /**< Indicates type of int. */
typedef unsigned int   HW_UINT; /**< Indicates type of unsigned int. */
typedef char           HW_CHAR; /**< Indicates type of char. */
typedef unsigned char  HW_UCHAR;/**< Indicates type of unsigned char. */
typedef int            HW_BOOL; /**< Indicates type of HW_BOOL. */
typedef void           HW_VOID; /**< Indicates type of void. */

#define IOTA_SUCCESS 0
#define IOTA_FAILURE -1
#define IOTA_PARAMETER_EMPTY -101
#define IOTA_RESOURCE_NOT_AVAILABLE -102
#define IOTA_INITIALIZATION_REPEATED -103
#define IOTA_LIBRARY_LOAD_FAILED -104
#define IOTA_SECRET_ENCRYPT_FAILED -105
#define IOTA_MQTT_CONNECT_FAILED -106
#define IOTA_MQTT_CONNECT_EXISTED -107
#define IOTA_CERTIFICATE_NOT_FOUND -108

#define IOTA_BUF_SIZE_64		64
#define IOTA_BUF_SIZE_128		128
#define IOTA_BUF_SIZE_256		256
#define IOTA_BUF_SIZE_512		512
#define IOTA_BUF_SIZE_1K		1024

typedef HW_VOID(*PFN_CALLBACK_HANDLER)(HW_VOID* context, HW_INT messageId, HW_INT code, HW_CHAR* message);
typedef HW_VOID(*PFN_CALLBACK_HANDLER_TOPIC)(HW_VOID* context, HW_INT messageId, HW_INT code, const HW_CHAR* topic, HW_CHAR* message);
typedef HW_VOID(*PFN_LOG_CALLBACK_HANDLER)(int level, char* format, va_list args);

//callback
static PFN_LOG_CALLBACK_HANDLER g_pfnLogCb = NULL;
static PFN_CALLBACK_HANDLER g_pfnCbConnectSuccess = NULL;
static PFN_CALLBACK_HANDLER g_pfnCbConnectFailure = NULL;
static PFN_CALLBACK_HANDLER g_pfnCbDisconnectSuccess = NULL;
static PFN_CALLBACK_HANDLER g_pfnCbDisconnectFailure = NULL;
static PFN_CALLBACK_HANDLER g_pfnCbConnectionLost = NULL;
static PFN_CALLBACK_HANDLER g_pfnCbPublishSuccess = NULL;
static PFN_CALLBACK_HANDLER g_pfnCbPublishFailure = NULL;
static PFN_CALLBACK_HANDLER g_pfnCbSubscribeSuccess = NULL;
static PFN_CALLBACK_HANDLER g_pfnCbSubscribeFailure = NULL;
static PFN_CALLBACK_HANDLER g_pfnCbCommandArrived = NULL;
static PFN_CALLBACK_HANDLER g_pfnCbDeviceAdditionResult = NULL;
static PFN_CALLBACK_HANDLER g_pfnCbDeviceDeletionResult = NULL;
static PFN_CALLBACK_HANDLER g_pfnCbDeviceUpdateResult = NULL;
static PFN_CALLBACK_HANDLER g_pfnCbDeviceQueryResult = NULL;

static PFN_CALLBACK_HANDLER_TOPIC g_pfnCallbackTopicHandler = NULL;


static HW_UINT g_uiPort = 0;
static HW_UINT g_uiUrlPrefix = 0;
static HW_UINT g_uiAuthMode = 0;
static HW_UINT g_uiLogLocalNumber = 0;
static HW_UINT g_uiLogLevel = 0;
static HW_UINT g_uiKeepaliveTime = 0;
static HW_UINT g_uiConnectTimeout = 0;
static HW_UINT g_uiRetryInterval = 0;
static HW_UINT g_uiQos = 0;

static HW_CHAR g_pcTopicTopoAdd[IOTA_BUF_SIZE_128] = { 0 };
static HW_CHAR g_pcTopicTopoAddResponse[IOTA_BUF_SIZE_128] = { 0 };
static HW_CHAR g_pcTopicTopoUpdate[IOTA_BUF_SIZE_128] = { 0 };
static HW_CHAR g_pcTopicTopoUpdateResponse[IOTA_BUF_SIZE_128] = { 0 };
static HW_CHAR g_pcTopicTopoDelete[IOTA_BUF_SIZE_128] = { 0 };
static HW_CHAR g_pcTopicTopoQuery[IOTA_BUF_SIZE_128] = { 0 };
static HW_CHAR g_pcTopicTopoQueryResponse[IOTA_BUF_SIZE_128] = { 0 };
static HW_CHAR g_pcTopicCommand[IOTA_BUF_SIZE_128] = { 0 };
static HW_CHAR g_pcTopicCommandResponse[IOTA_BUF_SIZE_128] = { 0 };
static HW_CHAR g_pcTopicDatas[IOTA_BUF_SIZE_128] = { 0 };

//mqtt
static MQTTAsync g_client = NULL;
static HW_CHAR g_pcWorkPath[IOTA_BUF_SIZE_512] = { 0 };
static HW_CHAR g_pcLogPath[IOTA_BUF_SIZE_512] = { 0 };
static HW_CHAR g_pcCertPath[IOTA_BUF_SIZE_512] = { 0 };
	
static HW_VOID subscribe(void);

static void writeLog(int level, char* format, ...)
{
    va_list vl;  
    va_start(vl, format); 
	if (g_pfnLogCb)
	{
		va_list vl;
		va_start(vl, format);
		g_pfnLogCb(level, format, vl);
	}
    else{
         // 使用 vprintf 来处理可变参数  
        vprintf(format, vl); 
    }
    va_end(vl); // 不要忘记结束 va_list  
}
static void delivered(void* context, MQTTAsync_token dt)
{
	writeLog(2, "Message with token value %d delivery confirmed\n", dt);
}

static void connlost(void* context, char* cause)
{
	writeLog(2, "Connection lost! cause: %s\n", cause);

	if (g_pfnCbConnectionLost)
	{
		g_pfnCbConnectionLost(NULL, 0, 0, cause);
        return;
	}
    MQTT_connect();
}

static void reportIPCAttrInfo(void);

static void onConnectSuccess(void* context, MQTTAsync_successData* response)
{
	writeLog(2, "onConnectSuccess! token: %d\n", response->token);

	if (g_pfnCbConnectSuccess)
	{
		g_pfnCbConnectSuccess(NULL, 0, 0, "");
	}

	subscribe();
    reportIPCAttrInfo();
}

static void onConnectFailure(void* context, MQTTAsync_failureData* response)
{
	writeLog(2, "onConnectFailure! token: %d, code: %d, message = %s\n", response->token, response->code, response->message);

	if (g_pfnCbConnectFailure)
	{
		g_pfnCbConnectFailure(NULL, 0, response->code, (HW_CHAR*)response->message);
        return;
	}
	sleep(3);
        MQTT_connect();
}

static void onSubscribeSuccess(void* context, MQTTAsync_successData* response)
{
	writeLog(2, "onSubscribeSuccess! token: %d\n", response->token);

	if (g_pfnCbSubscribeSuccess)
	{
		g_pfnCbSubscribeSuccess(NULL, 0, 0, "");
	}
}

static void onSubscribeFailure(void* context, MQTTAsync_failureData* response)
{
	writeLog(2, "onSubscribeFailure! token: %d, code: %d, message = %s\n", response->token, response->code, response->message);

	if (g_pfnCbSubscribeFailure)
	{
		g_pfnCbSubscribeFailure(NULL, 0, response->code, (HW_CHAR*)response->message);
	}
}

static void onDisconnectSuccess(void* context, MQTTAsync_successData* response)
{
	writeLog(2, "onDisconnectSuccess! token: %d\n", response->token);

	if (g_pfnCbDisconnectSuccess)
	{
		g_pfnCbDisconnectSuccess(NULL, 0, 0, "");
	}
}

static void onDisconnectFailure(void* context, MQTTAsync_failureData* response)
{
	writeLog(2, "onDisconnectFailure! token: %d, code: %d, message = %s\n", response->token, response->code, response->message);

	if (g_pfnCbDisconnectFailure)
	{
		g_pfnCbDisconnectFailure(NULL, 0, response->code, (HW_CHAR*)response->message);
	}
}

static void onSendSuccess(void* context, MQTTAsync_successData* response)
{
	writeLog(2, "onSendSuccess! token: %d\n", response->token);

	if (g_pfnCbPublishSuccess)
	{
		g_pfnCbPublishSuccess(NULL, 0, 0, "");
	}
}

static void onSendFailure(void* context, MQTTAsync_failureData* response)
{
	writeLog(2, "onSendFailure! token: %d, code: %d, message = %s\n", response->token, response->code, response->message);

	if (g_pfnCbPublishFailure)
	{
		g_pfnCbPublishFailure(NULL, 0, response->code, (HW_CHAR*)response->message);
	}
}

static HW_VOID subscribe(void)
{
    strcpy(g_pcTopicCommand,RPC_REQUEST_TOPIC);
	HW_CHAR* arraySubs[4];
	arraySubs[0] = g_pcTopicTopoAddResponse;
	arraySubs[1] = g_pcTopicTopoUpdateResponse;
	arraySubs[2] = g_pcTopicTopoQueryResponse;
	arraySubs[3] = g_pcTopicCommand;


    

	HW_INT iRet = IOTA_SUCCESS;
	for (int i = 0; i < 4; i++)
	{
        if(strlen(arraySubs[i])==0)
            continue;

		MQTTAsync_responseOptions opts = MQTTAsync_responseOptions_initializer;
		opts.onSuccess = onSubscribeSuccess;
		opts.onFailure = onSubscribeFailure;
		opts.context = NULL;
		iRet = MQTTAsync_subscribe(g_client, arraySubs[i], g_uiQos, &opts);
		if (iRet != MQTTASYNC_SUCCESS)
		{
			writeLog(2, "Failed to subscribe, return code %d\n", iRet);
		}
		else
		{
			writeLog(2, "MQTTAsync_subscribe, topic: %s\n", arraySubs[i]);
		}
	}
}


static HW_INT publishMessage(HW_CHAR* pcTopicName, HW_CHAR* pcMessage)
{
	HW_INT iRet = IOTA_SUCCESS;
	MQTTAsync_message pubmsg = MQTTAsync_message_initializer;
	MQTTAsync_token token;

	pubmsg.payload = (void*)pcMessage;
	pubmsg.payloadlen = strlen(pcMessage);
	pubmsg.qos = g_uiQos;
	pubmsg.retained = 0;

	MQTTAsync_responseOptions opts = MQTTAsync_responseOptions_initializer;
	opts.onSuccess = onSendSuccess;
	opts.onFailure = onSendFailure;
	opts.context = NULL;
	iRet = MQTTAsync_sendMessage(g_client, pcTopicName, &pubmsg, &opts);
	if (iRet != MQTTASYNC_SUCCESS)
	{
		writeLog(2, "Failed to publish message, return code %d\n", iRet);
		iRet = IOTA_FAILURE;
	}
	else
	{
		writeLog(2, "MQTTAsync_sendMessage, topic: %s, msg: %s\n", pcTopicName, pcMessage);
	}

	return iRet;
}

HW_VOID IOTA_destroy()
{
	MQTTAsync_destroy(&g_client);
}

int MQTT_connect()
{
    MQTTAsync_SSLOptions ssl_opts = MQTTAsync_SSLOptions_initializer;
    ssl_opts.trustStore = strlen(g_pcCertPath) == 0 ? "./mqttClientTrustCert.pem" : g_pcCertPath;
    ssl_opts.sslVersion = MQTT_SSL_VERSION_DEFAULT;

    MQTTAsync_connectOptions conn_opts = MQTTAsync_connectOptions_initializer;
    conn_opts.keepAliveInterval = 20;
    conn_opts.onSuccess = onConnectSuccess;
    conn_opts.onFailure = onConnectFailure;
    conn_opts.username = TOKEN;
    conn_opts.password = NULL;
    conn_opts.context = NULL;
    conn_opts.ssl = &ssl_opts;
    int iRet = MQTTAsync_connect(g_client, &conn_opts);
    if (iRet != MQTTASYNC_SUCCESS)
    {
        writeLog(2, "Failed to connect, return code %d\n", iRet);
    }
    return iRet;
}

HW_INT IOTA_login()
{
	HW_INT iRet = IOTA_SUCCESS;
	
	HW_BOOL bCreate = HW_FALSE, bSet = HW_FALSE, bConnect = HW_FALSE;

	do
	{
		if (g_client == NULL)
		{
            char client_id[24];
            snprintf(client_id, sizeof(client_id), "client_%ld", time(NULL));
    		iRet = MQTTAsync_create(&g_client, ADDRESS, client_id, MQTTCLIENT_PERSISTENCE_NONE, NULL);
			if (iRet != MQTTASYNC_SUCCESS)
			{
				writeLog(2, "Failed to create client, return code %d\n", iRet);
				break;
			}
			bCreate = HW_TRUE;
			iRet = MQTTAsync_setCallbacks(g_client, NULL, connlost, msgarrvd, delivered);
			if (iRet != MQTTASYNC_SUCCESS)
			{
				writeLog(2, "Failed to set callbacks, return code %d\n", iRet);
				break;
			}
			bSet = HW_TRUE;
		}
		else
		{
			bCreate = HW_TRUE;
			bSet = HW_TRUE;
		}

        MQTT_connect();
		bConnect = HW_TRUE;
	} while (false);

	if (!bSet && bCreate)
	{
		IOTA_destroy();
	}

	return iRet;
}


HW_INT IOTA_logout()
{
	HW_INT iRet = IOTA_SUCCESS;

	MQTTAsync_disconnectOptions disconn_opts = MQTTAsync_disconnectOptions_initializer;
	disconn_opts.onSuccess = onDisconnectSuccess;
	disconn_opts.onFailure = onDisconnectFailure;
	disconn_opts.context = NULL;
	iRet = MQTTAsync_disconnect(g_client, &disconn_opts);
	if (iRet != MQTTASYNC_SUCCESS)
	{
		writeLog(2, "Failed to disconnect, return code %d\n", iRet);
	}

	return iRet;
}

static void processGetIPCStaticInfo(const char *cmdName)
{
    if (strcmp(cmdName, "static info") != 0) {
        return;
    }

    cJSON *info = cJSON_CreateObject();
    getOSStaticInfo(info);
    publishMessage(TELEMETRY_TOPIC,(void *)cJSON_PrintUnformatted(info));
    cJSON_Delete(info);
}

static void reportIPCAttrInfo(void)
{
    cJSON *info = cJSON_CreateObject();
    getOSStaticInfo(info);
    publishMessage(TOPIC_ATTRS_EX,(void *)cJSON_PrintUnformatted(info));
    cJSON_Delete(info);
}


static int msgarrvd(void* context, char* topicName, int topicLen, MQTTAsync_message* message)
{
	int iRet = 1;
	((char*)message->payload)[message->payloadlen] = '\0';
	writeLog(2, "Message arrived, topic: %s, len: %d, msgid: %d, message: %s\n", topicName, message->payloadlen, message->msgid, (char*)message->payload);

	HW_BOOL bRet = HW_FALSE;
	HW_UINT uiMid = 0;
	HW_INT iStatusCode = 0;
	HW_CHAR pcStatusDecs[IOTA_BUF_SIZE_64] = { 0 };

  // 检查是否为 RPC 请求
  if (strstr(topicName, RPC_REQUEST_PREFIX) != NULL)
  {
    char *request_id = strrchr(topicName, '/') + 1;
    cJSON *request_body = cJSON_Parse(message->payload);

    cJSON *method = cJSON_GetObjectItem(request_body, "method");

    const char *methodVal = cJSON_GetStringValue(method);
    processGetIPCStaticInfo(methodVal);

    // 处理升级请求
    if (strcmp(cJSON_GetStringValue(method), "update") == 0)
    {
      // 获取固件信息并下载 OTA 包
      get_firmware_info_and_download();

      bool upgrade_success = true;
      cJSON *telemetry = cJSON_CreateObject();

      // 模拟升级过程并发送进度
      for (int progress = 0; progress <= 100; progress += 20)
      {
        sleep(1);
        cJSON_AddNumberToObject(telemetry, "upgrade_progress", progress);
        publishMessage(TELEMETRY_TOPIC,(void *)cJSON_Print(telemetry));
      }

      // 发送升级结果
      if (upgrade_success)
      {
        cJSON_AddStringToObject(telemetry, "upgrade_status", "done");
      }
      else
      {
        cJSON_AddStringToObject(telemetry, "upgrade_status", "failed");
      }

      publishMessage(TELEMETRY_TOPIC,(void *)cJSON_Print(telemetry));

      cJSON_Delete(telemetry);
    }

    cJSON_Delete(request_body);
  }


	MQTTAsync_freeMessage(&message);
	MQTTAsync_free(&topicName);

	return iRet;
}

#if 0
int main(int argc, char *argv[]) 
#else
int mqtt_ota_demo(void) 
#endif

{
    IOTA_login();

    // 保持程序运行，发送遥测数据
    while (true) {
        // 这里可以添加发送遥测数据的代码
        //sleep(30);
        (void)pause();
        //publishMessage(TELEMETRY_TOPIC, "{\"PA\":\"22.54845664\",\"TEM\":\"114.06455184\"}");
    }


    IOTA_logout();
    IOTA_destroy();

    return 0;
}

